﻿// Decompiled with JetBrains decompiler
// Type: DnProcessSimulateCommands.CApAPPOptimizeCycleTimeCommand
// Assembly: DnProcessSimulateCommands, Version=2402.0.0.890, Culture=neutral, PublicKeyToken=null
// MVID: A885D881-AEDF-447E-852A-6F13102E089C
// Assembly location: C:\Program Files\Tecnomatix_2402\eMPower\DotNetCommands\DnProcessSimulateCommands.dll

using DnProcessSimulateCommands.AutomaticPathPlanner;
using DnProcessSimulateCommands.AutomaticPathPlanner.Planner;
using EngineeringInternalExtension;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Windows.Forms;


namespace DnProcessSimulateCommands;

public class CApAPPOptimizeCycleTimeCommand : CApAPPPlanCommandBase
{
  private List<CApAPPSegmentCTOCommand> m_allThreadedCTOCommand;
  private int m_currentTaskIndex;
  private long m_lastRefreshTime;
  private Stopwatch m_elapsedTimer;

  public CApAPPOptimizeCycleTimeCommand(
    List<CApAPPTask> i_tasks,
    KiAppPathPlanningParamsEx i_pathPlanningParams)
    : base(i_tasks, i_pathPlanningParams)
  {
    this.m_currentTaskIndex = -1;
    this.m_allThreadedCTOCommand = new List<CApAPPSegmentCTOCommand>();
    this.m_elapsedTimer = new Stopwatch();
    this.PlanningWasCancelled = false;
  }

  public override void Cancel() => this.PlanningWasCancelled = true;

  public override double GetProgress()
  {
    double num1 = 0.0;
    double num2 = (double) this.CountSubProblems();
    for (int index = 0; index < this.m_currentTaskIndex; ++index)
      num1 += 1.0 / num2;
    return num1 + this.GetProgress(this.m_currentTaskIndex) / num2;
  }

  public override double GetProgress(int i_subtaskRank)
  {
    double progress = 0.0;
    if (i_subtaskRank <= this.m_currentTaskIndex)
      progress = this.m_allThreadedCTOCommand[i_subtaskRank].GetProgress();
    return progress;
  }

  public bool GetTimeOutReached()
  {
    bool o_isTimeOutReached = false;
    if (this.m_allThreadedCTOCommand.Count != 0 && this.m_allThreadedCTOCommand[this.m_currentTaskIndex] is CApAPPSegmentNewFullCTOCommand newFullCtoCommand)
      newFullCtoCommand.GetTimeOutReached(ref o_isTimeOutReached);
    return o_isTimeOutReached;
  }

  protected override bool DoStart(
    ref CApAPPPlanCommandBase.PlanSuccessEventArgs errEvtArgs)
  {
    try
    {
      bool o_trackEndReached = false;
      bool flag = false;
      bool i_success = false;
      for (int index = 0; index < this.TasksToPlan.Count; ++index)
      {
        if (!(this.TasksToPlan[index] as CApAPPRoboticTask).AreZonesWellDefined())
        {
          this.NotifyEndPlanning((object) this, new CApAPPPlanCommandBase.PlanSuccessEventArgs(false, this.PathPlanningParams.OptimizationOption != 3 ? CApAPPMainWindowStringTable.ZoneDefinitionErrorTitleCycleTime : CApAPPMainWindowStringTable.ZoneDefinitionErrorTitleEnergy, CApAPPMainWindowStringTable.ZoneDefinitionErrorMsg));
          return false;
        }
      }
      List<string> o_errorMessages = new List<string>();
      while (!flag && !this.PlanningWasCancelled)
      {
        i_success = this.StartNextOptimize(ref o_trackEndReached, ref o_errorMessages);
        if (i_success)
        {
          if (o_trackEndReached)
          {
            flag = true;
          }
          else
          {
            while (!this.m_allThreadedCTOCommand[this.m_currentTaskIndex].IsFinished() && !this.PlanningWasCancelled)
            {
              this.m_allThreadedCTOCommand[this.m_currentTaskIndex].onIdle();
              this.RefreshProgressUI();
            }
            if (this.PlanningWasCancelled && !this.m_allThreadedCTOCommand[this.m_currentTaskIndex].IsFinished())
              this.m_allThreadedCTOCommand[this.m_currentTaskIndex].Cancel();
          }
        }
        else
          flag = true;
      }
      if (!i_success)
      {
        string i_details = this.ProcessCTOErrorMessages(o_errorMessages);
        errEvtArgs = new CApAPPPlanCommandBase.PlanSuccessEventArgs(false, CApAPPMainWindowStringTable.OptimizationErrorTitle, i_details);
      }
      else
        errEvtArgs = new CApAPPPlanCommandBase.PlanSuccessEventArgs(true);
      this.EndPlanning(i_success, errEvtArgs);
      return i_success;
    }
    catch
    {
      errEvtArgs = new CApAPPPlanCommandBase.PlanSuccessEventArgs(false, CApAPPMainWindowStringTable.OptimizationErrorTitle, CApAPPMainWindowStringTable.InternalErrorMessage);
      this.EndPlanning(false, errEvtArgs);
      return false;
    }
  }

  private void RefreshProgressUI()
  {
    if (this.m_elapsedTimer.ElapsedMilliseconds - this.m_lastRefreshTime <= 500L)
      return;
    this.m_lastRefreshTime = this.m_elapsedTimer.ElapsedMilliseconds;
    this.UpdateProgress((object) this, new EventArgs());
    Application.DoEvents();
  }

  public bool StartNextOptimize(ref bool o_trackEndReached, ref List<string> o_errorMessages)
  {
    bool flag = true;
    ++this.m_currentTaskIndex;
    o_trackEndReached = false;
    if (this.m_currentTaskIndex >= this.TasksToPlan.Count)
    {
      o_trackEndReached = true;
    }
    else
    {
      this.m_allThreadedCTOCommand.Add(this.DoCreateThreadCommand(this.TasksToPlan[this.m_currentTaskIndex], this.PathPlanningParams));
      this.m_elapsedTimer.Start();
      flag = this.m_allThreadedCTOCommand[this.m_allThreadedCTOCommand.Count - 1].StartPlanning(ref o_errorMessages);
      if (!flag)
        this.m_elapsedTimer.Reset();
    }
    return flag;
  }

  protected virtual CApAPPSegmentCTOCommand DoCreateThreadCommand(
    CApAPPTask i_task,
    KiAppPathPlanningParamsEx i_pathPlanningParams)
  {
    if (i_pathPlanningParams.CTOMode == 1 || i_pathPlanningParams.OptimizationOption == 3)
      return (CApAPPSegmentCTOCommand) new CApAPPSegmentFullCTOCommand(i_task, i_pathPlanningParams);
    return i_pathPlanningParams.CTOMode == 2 ? (CApAPPSegmentCTOCommand) new CApAPPSegmentNewFullCTOCommand(i_task, i_pathPlanningParams) : new CApAPPSegmentCTOCommand(i_task, i_pathPlanningParams);
  }

  private void EndPlanning(
    bool i_success,
    CApAPPPlanCommandBase.PlanSuccessEventArgs planSuccessEventArgs)
  {
    IList<Tuple<CApAPPTask, double>> fitnessGainPerTask = this.GetFullCTOFitnessGainPerTask();
    foreach (CApAPPTask task in this.TasksToPlan)
    {
      if (task is CApAPPRoboticTask && this.PathPlanningParams.CTOMode == null)
        (task as CApAPPRoboticTask).UpdateTxOperationZones();
      else if (this.PathPlanningParams.CTOMode == 2)
      {
        task.UpdateTxOperation();
        if (task is CApAPPRoboticTask capAppRoboticTask)
          capAppRoboticTask.UpdateTxOperationZones();
      }
      else if (this.RetrieveTaskFitnessGainFromTasks(fitnessGainPerTask, task) < 0.0)
        task.UpdateTxOperation();
    }
    this.NotifyEndPlanning((object) this, planSuccessEventArgs);
    foreach (CApAPPTask capAppTask in this.TasksToPlan)
      capAppTask.RestoreInitialState();
  }

  public override int RetrieveIndexSubProblemFromWaypoint(CApAPPWaypoint i_wp) => 0;

  public override int CountSubProblems() => this.TasksToPlan.Count;

  public override long GetElapsedTime() => this.m_elapsedTimer.ElapsedMilliseconds;

  public override bool IsFinished(int i_subtaskRank)
  {
    bool flag = false;
    if (i_subtaskRank <= this.m_currentTaskIndex)
      flag = this.m_allThreadedCTOCommand[i_subtaskRank].IsFinished();
    return flag;
  }

  internal override void AfterPlanningFailure()
  {
    foreach (CApAPPSegmentCTOCommand segmentCtoCommand in this.m_allThreadedCTOCommand)
      segmentCtoCommand.UnFreezeOperationTree();
  }

  public IList<Tuple<CApAPPTask, double>> GetFullCTOFitnessGainPerTask()
  {
    IList<Tuple<CApAPPTask, double>> fitnessGainPerTask = (IList<Tuple<CApAPPTask, double>>) new List<Tuple<CApAPPTask, double>>();
    foreach (CApAPPSegmentCTOCommand segmentCtoCommand in this.m_allThreadedCTOCommand)
    {
      if (segmentCtoCommand is CApAPPSegmentFullCTOCommand)
        fitnessGainPerTask.Add(new Tuple<CApAPPTask, double>(segmentCtoCommand.taskToPlan, (segmentCtoCommand as CApAPPSegmentFullCTOCommand).FitnessGain));
    }
    return fitnessGainPerTask;
  }

  public double RetrieveTaskFitnessGainFromTasks(
    IList<Tuple<CApAPPTask, double>> gains,
    CApAPPTask task)
  {
    double num = 0.0;
    bool flag = false;
    for (int index = 0; !flag && index < gains.Count; ++index)
    {
      if (gains[index].Item1 == task)
        num = gains[index].Item2;
    }
    return num;
  }

  private string ProcessCTOErrorMessages(List<string> errorMessages)
  {
    StringBuilder stringBuilder = new StringBuilder();
    List<string> collisionErrorMessages = new List<string>();
    List<string> simulationErrorMessages = new List<string>();
    this.ExtractCTOErrorMessagesFromList(errorMessages, ref collisionErrorMessages, ref simulationErrorMessages);
    int count1 = collisionErrorMessages.Count;
    int count2 = simulationErrorMessages.Count;
    if (count1 > 0)
    {
      stringBuilder.AppendLine(CApAPPMainWindowStringTable.OptimizationCollisionError);
      foreach (string str in collisionErrorMessages)
        stringBuilder.AppendLine($"    {str}");
      if (count2 > 0)
        stringBuilder.AppendLine(this.GetNewLineSeparator());
    }
    if (count2 > 0)
    {
      bool flag = false;
      foreach (string str in simulationErrorMessages)
      {
        if (!flag)
        {
          stringBuilder.AppendLine(CApAPPMainWindowStringTable.OptimizationSimulationError);
          flag = true;
        }
        stringBuilder.AppendLine();
        stringBuilder.AppendLine(str);
      }
    }
    return stringBuilder.ToString();
  }

  private void ExtractCTOErrorMessagesFromList(
    List<string> errorMessages,
    ref List<string> collisionErrorMessages,
    ref List<string> simulationErrorMessages)
  {
    string str = "found collision at index ";
    foreach (string errorMessage in errorMessages)
    {
      if (errorMessage.Contains(str))
      {
        int result = 0;
        if (int.TryParse(errorMessage.Substring(errorMessage.IndexOf(str) + str.Length), out result))
          collisionErrorMessages.Add(this.ConvertFirstWayPointIndexToWayPointsString(result));
      }
      else
        simulationErrorMessages.Add(errorMessage);
    }
  }

  private string ConvertFirstWayPointIndexToWayPointsString(int wayPointIndex)
  {
    string wayPointsString = "[Unknown waypoint]";
    if (wayPointIndex >= 0 && wayPointIndex < this.m_allThreadedCTOCommand[this.m_allThreadedCTOCommand.Count - 1].taskToPlan.CountWaypoints())
      wayPointsString = $"{this.m_allThreadedCTOCommand[this.m_allThreadedCTOCommand.Count - 1].taskToPlan.Waypoint(wayPointIndex).Name} - {this.m_allThreadedCTOCommand[this.m_allThreadedCTOCommand.Count - 1].taskToPlan.Waypoint(wayPointIndex + 1).Name}";
    return wayPointsString;
  }

  private string GetNewLineSeparator() => "________________________________________";

  public CApAPPTask CurrentTask
  {
    get
    {
      CApAPPTask currentTask = (CApAPPTask) null;
      if (this.m_currentTaskIndex >= 0 && this.m_currentTaskIndex < this.TasksToPlan.Count)
        currentTask = this.TasksToPlan[this.m_currentTaskIndex];
      return currentTask;
    }
  }

  internal bool GetFitnessGain(
    ref int currentSegmentIndex,
    ref double currentSegmentGain,
    ref double globalGain)
  {
    bool fitnessGain = true;
    if (this.m_allThreadedCTOCommand.Count == 0)
      fitnessGain = false;
    if (fitnessGain)
      fitnessGain = this.m_allThreadedCTOCommand[this.m_allThreadedCTOCommand.Count - 1] is CApAPPSegmentFullCTOCommand && (this.m_allThreadedCTOCommand[this.m_allThreadedCTOCommand.Count - 1] as CApAPPSegmentFullCTOCommand).GetCurrentGain(ref currentSegmentIndex, ref currentSegmentGain, ref globalGain);
    return fitnessGain;
  }

  internal bool GetCycleTimeResult(ref double currentResult)
  {
    bool cycleTimeResult = true;
    if (this.m_allThreadedCTOCommand.Count == 0)
      cycleTimeResult = false;
    if (cycleTimeResult)
      cycleTimeResult = this.m_allThreadedCTOCommand[this.m_currentTaskIndex] is CApAPPSegmentNewFullCTOCommand newFullCtoCommand && newFullCtoCommand.GetCurrentResult(ref currentResult);
    return cycleTimeResult;
  }

  public string BuildEndOptimizationMessage()
  {
    StringBuilder stringBuilder = new StringBuilder();
    foreach (CApAPPSegmentCTOCommand segmentCtoCommand in this.m_allThreadedCTOCommand)
    {
      if (segmentCtoCommand is CApAPPSegmentNewFullCTOCommand newFullCtoCommand)
      {
        CApAPPTask taskToPlan = newFullCtoCommand.taskToPlan;
        if (newFullCtoCommand.OptimizationStatus == 3)
          stringBuilder.Append(string.Format(CApAPPMainWindowStringTable.OptimizationCanceled, (object) taskToPlan.Name));
        else if (newFullCtoCommand.OptimizationStatus == 5)
          stringBuilder.Append(CApAPPMainWindowStringTable.OptimizationInternalError);
        else if (newFullCtoCommand.OptimizationStatus == 7 && newFullCtoCommand.InitialCycleTime == newFullCtoCommand.ResultCycleTime)
          stringBuilder.Append(string.Format(CApAPPMainWindowStringTable.OptimizationAllSegmentsSkipped, (object) taskToPlan.Name));
        else if (newFullCtoCommand.OptimizationStatus == null || newFullCtoCommand.OptimizationStatus == 1 || newFullCtoCommand.OptimizationStatus == 2 || newFullCtoCommand.OptimizationStatus == 6)
        {
          double resultCycleTime = newFullCtoCommand.ResultCycleTime;
          stringBuilder.Append(CApAPPMainWindowStringTable.CycleTimeResultAfterOptimization);
          if (this.m_allThreadedCTOCommand.Count == 1)
            stringBuilder.Append($"{Math.Round(resultCycleTime, 2)}s. ");
          else
            stringBuilder.Append($"{taskToPlan.Name} {Math.Round(resultCycleTime, 2)}s. ");
          if (newFullCtoCommand.HasInitialCycleTime)
          {
            double num = 100.0 * (newFullCtoCommand.InitialCycleTime - newFullCtoCommand.ResultCycleTime) / newFullCtoCommand.InitialCycleTime;
            stringBuilder.Append(string.Format(CApAPPMainWindowStringTable.OptimizationInitialCycleTimeAndGain, (object) Math.Round(num, 2)));
          }
          if (newFullCtoCommand.OptimizationStatus != null)
          {
            if (newFullCtoCommand.OptimizationStatus == 2)
            {
              stringBuilder.Append(CApAPPMainWindowStringTable.OptimizationProgressStoppedDetailMessage);
              if (newFullCtoCommand.PathPlanningParams.IsOptimizationCycleTimeTargetEnabled)
              {
                stringBuilder.AppendLine();
                stringBuilder.Append(CApAPPMainWindowStringTable.OptimizationCannotReachTargetCycleTime);
              }
            }
            else if (newFullCtoCommand.OptimizationStatus == 1)
              stringBuilder.Append(CApAPPMainWindowStringTable.OptimizationTimeOutReachedDetailMessage);
            else if (newFullCtoCommand.OptimizationStatus == 6)
              stringBuilder.Append(CApAPPMainWindowStringTable.OptimizationAlreadyUnderTarget);
          }
          if (newFullCtoCommand.HasSkippedCollidingSegments)
          {
            stringBuilder.AppendLine();
            stringBuilder.Append(CApAPPMainWindowStringTable.OptimizationSkippedCollidingSegments);
          }
        }
        stringBuilder.AppendLine();
      }
    }
    return stringBuilder.ToString();
  }
}
